Mybatis笔记
Mybatis开始
SQL语句输出方式
1.在全局配置文件中,配置标签
<settings> <setting name="logImpl" value="STDOUT_LOGGING"/> </settings>
2.使用log4j等工具,进行输出
mapper中传递参数方式
#{}和${}的区别 #{}表示占位符的方式拼接sql语句 占位符为"?" ${}表示拼接字符串的方式拼接sql语句 ${}很少用
<select id="selAll" resultType="com.bjsxt.pojo.People" parameterType="int"> select *from People where id=#{0} //传入参数为 的时候 使用索引 占位符选择0位置第一个参数 当传入参数只有一个的时候,#{}大括号中内容可以位任意字符 select *from People where id=#{param1}//param+数字表示第几个参数,从1开始 select *from People where id=#{0}//此时不使用索引 单纯的id=0 </select> <select id="selAll" resultType="com.bjsxt.pojo.People" parameterType="com.bjsxt.pojo.People"> select *from People where id=#{id} select *from People where id=${id}//若使用拼接字符串方式,则需要传入为对象,mybatis自动在传入的对象中寻找对应名字的getset方法来获取值 </select> <select id="selAll" resultType="com.bjsxt.pojo.People" parameterType="java.util.Map"> select *from People where id=#{key} //#{}中填写map的key </select>
全局配置文件解释
1.1 <transactionManager/> type 属性可取值 1.1.1 JDBC,事务管理使用 JDBC 原生事务管理方式 1.1.2 MANAGED 把事务管理转交给其他容器,如交给Spring进行管理.原生JDBC 事务 setAutoMapping(false); 1.2 <dataSouce/>type 属性 1.2.1 POOLED 使用数据库连接池 1.2.2 UNPOOLED 不实用数据库连接池,和直接使用 JDBC 一样 1.2.3 JNDI :java 命名目录接口技术.
例子:
<configuration> <!-- default引用environment的id,当前所使用的环境 --> <environments default="default"> <!-- 声明可以使用的环境 --> <environment id="default"> <!-- 使用原生JDBC事务 --> <transactionManager type="JDBC"></transactionManager> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/ssm"/> <property name="username" value="root"/> <property name="password" value="yu752949273"/> </dataSource> </environment> </environments>
绝对路径
如果是请求转发 / 表示项目根目录(WebContent) 其他重定向,<img/> <script/>,<style/>,location.href 等/都表示服务器根目录(tomcat/webapps 文件夹) 如果客户端请求的控制器,控制器转发到JSP后,jsp中如果使用相对路径,需要按照控制器的路径去找其他资源. 尽量使用绝对路径 避免相对路径与控制器路径冲突的问题
mybatis与ibatis的区别
版本
2.x为ibatis 3.x为mybatis
全局配置文件中
ibatis中使用sqlMap元素,mybatis中使用mappers元素 ibatis中根元素是sqlMapConfig,mybatis中是configuration settings中属性配置不同
ibatis中为
<settings 属性1="属性值1" 属性2="属性值2" 属性x="属性值x"/>
mybatis中为
<settings>
<setting name="属性1" value="属性值1"/>
<setting name="属性2" value="属性值2"/>
<setting name="属性x" value="属性值x"/>
</settings>
映射文件中
ibatis中使用sqlMap元素,mybatis中使用mapper元素
resultMap
当返回值类型为resultMap时,需要在mapper中编写resultMap与实体类中的属性向映射,其中 一对一association 一对多,多对多collection
<association property="" column="" select=""></association> <!--property为映射实体类中属性 column为数据库中属性列 select为子查询id--> <collection property="" column="" ofType="" select=""></collection> <!--property为映射实体类中属性 column为数据库中属性列 select为子查询id ofType为另一对多的实体类-->
动态sql
标签
<where> <set> <if test="a!=null and a!=''"> <trim> <bind> <choose><when><otherwise> <sql><include> <foreach>
<where>标签
先去掉条件的第一个and 然后添加where 当where中的条件不存在时 where标签也不存在
<select id="selByAccinAccout" resultType="log"> select * from log <where> <if test="accin!=null and accin!=''"> and accin=#{accin} </if> <if test="accout!=null and accout!=''"> and accout=#{accout} </if> </where> </select>
<set>标签
先去掉条件的最后一个逗号 然后在最前面添加set 当set中的条件不存在时 set标签也不存在
<update id="upd" parameterType="log" > update log <set> id=#{id}, <if test="accIn!=null and accIn!=''"> accin=#{accIn}, </if> <if test="accOut!=null and accOut!=''"> accout=#{accOut}, </if> </set> where id=#{id} </update>
<if>标签
若不满足条件则该字句不存在 test等于的字符串中,若条件为多个,则用and或or连接 不是&或|
<if test="accin!=null and accin!=''">
and accin=#{accin}
</if>
<trim>标签
prefix 在前面添加内容 prefixOverrides 去掉前面内容 suffix 在后面添加内容 suffixOverrieds 去掉后面内容 执行顺序为 先去掉内容 再添加内容
<update id="upd" parameterType="log"> update log <trim prefix="set" suffixOverrides=","> a=a, </trim> where id=100 </update>
<bind>标签
为传递的变量拼接字符
<bind name="aaa" value="'$'+aaa"/>
<choose><when><otherwise>标签
<choose> <when test="a!=null"> </when> </choose> <choose> <when test="b!=null"> </when> </choose>
只要有一个成立,其他都不执行. 若存在多个能够成立的,则只执行成立的第一个
choose标签是按顺序判断其内部when标签中的test条件出否成立,如果有一个成立,则 choose 结束。当 choose 中所有 when 的条件都不满则时,则执行 otherwise 中的sql。
<sql><include>标签
sql片段 复用 <sql id="a"></sql> <include refid="a"></include>
<foreach>标签
<foreach collection="" item="" index="" open="" close="" separator="">
</foreach>
foreach 也就是遍历迭代,在SQL中通常用在 in 这个关键词的后面
foreach元素的属性主要有 item,index,collection,open,separator,close。
分别代表:
而最为重要的就是collection属性了,既然是迭代就表示传入的参数是多个,这时候传入的参数就有以下几种可能:
1. 传入的参数为list的时候
对应的Dao中的Mapper文件是:
对应的Dao中的Mapper文件是:
public List<User> selectByIds(int[] ids);
xml文件代码片段:
public List<User> selectByIds(Map<String, Object> params);
xml文件代码片段:
ThreadLocal线程容器
给线程绑定一个Object容器,若线程状态不变则可以随时取出,若线程发生改变,则无法取出.
final ThreadLocal<String> threadLocal = new ThreadLocal<>(); threadLocal.set("测试"); new Thread(){ public void run() { String result = threadLocal.get(); System.out.println("结果:"+result);//线程改变无法取出 }; }.start(); String result = threadLocal.get(); System.out.println("结果:"+result);//可以取出
主要用于同一Servlet线程,静态加载SqlSessionFactory
工具类:
import java.io.IOException; import java.io.InputStream; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; public class MyBatisUtil { //factory实例化的过程是一个比较耗费性能的过程. //保证有且只有一个factory private static SqlSessionFactory factory; private static ThreadLocal<SqlSession> tl = new ThreadLocal<>(); static{ try { InputStream is = Resources.getResourceAsStream("mybatis.xml"); factory = new SqlSessionFactoryBuilder().build(is); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 获取SqlSession的方法 */ public static SqlSession getSession(){ SqlSession session = tl.get(); if(session==null){ tl.set(factory.openSession()); } return tl.get(); } public static void closeSession(){ SqlSession session = tl.get(); if(session!=null){ session.close(); } tl.set(null); } }
拦截器:
import java.io.IOException; import java.io.InputStream; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.annotation.WebFilter; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import com.bjsxt.util.MyBatisUtil; /** * 最开始是由Spring框架提出的.整合Hibernate框架是使用的是OpenSessionInView * * * @author Administrator * */ @WebFilter("/*") public class OpenSessionInView implements Filter{ @Override public void init(FilterConfig filterconfig) throws ServletException { } @Override public void doFilter(ServletRequest servletrequest, ServletResponse servletresponse, FilterChain filterchain) throws IOException, ServletException { SqlSession session = MyBatisUtil.getSession(); try { filterchain.doFilter(servletrequest, servletresponse);//允许servlet执行,而允许service执行 session.commit(); } catch (Exception e) { session.rollback(); e.printStackTrace(); }finally{ MyBatisUtil.closeSession(); } } @Override public void destroy() { } }
缓存
MyBatis 中默认 SqlSession 缓存开启
SqlSession 缓存必须是同一个SqlSession 对象
同一个 SqlSession 对象调用同一个时,只有第一次访问数据库,第一次之后把查询结果缓存到 SqlSession 缓存区(内存)中
缓存流程
步骤一: 先去缓存区中找是否存在 statement(<select>) 步骤二:返回结果 步骤三:如果没有缓存 statement 对象,去数据库获取数据 步骤四:数据库返回查询结果 步骤五:把查询结果放到对应的缓存区中
SqlSessionFactory 缓存
比 SqlSession 缓存高一级的二级缓存,默认关闭 开启方法再mapper.xml的mapper中添加标签:
<mapper namespace="com.bjsxt.mapper.LogMapper"> <cache readOnly="true"></cache> <insert id="ins" parameterType="log"> insert into log values(default,#{accOut},#{accIn},#{money}) </insert> </mapper>
只有当SqlSession在commit()或close()的时候才会将SqlSession缓存提交到SqlSessionFactory缓存中
Mybatis运行原理
运行过程中需要用到的类:
Resource 加载Mybatis全局配置文件的IO流工具
SqlSessionFactoryBuilder() 创建SqlSessionFactory接口的实现类
XMLConfigBuilder 读取全局配置文件的流内容,转换为JAVA代码
Configuration 由XMLConfigBuilder 创建,封装了全局配置文件中所有的属性信息
DefaultSqlSessionFactory 是SqlSessionFactory接口的实现类
Transaction 事务类 每一个Session都会创建一个Transaction对象进行事务管理
TransactionFactory 事务工厂,负责生产事务类
Executor Mybatis执行器 一般使用SimpleExecutor实现类,批量操作时,使用BatchExecutor 通过OpenSession的参数控制 负责执行SQL命令 相当于JDBC 中的statement对象或preparedStatement对象或callableStatement对象